package org.gl.gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

import org.gl.logic.GLActions;
import org.gl.logic.GLMapLogic;
import org.gl.logic.Rule01Logic;
import org.gl.obj.GLMap;

public class GLWindow extends JFrame implements Runnable, ActionListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private GLPanel panel;
	private GLMap map;
	private GLMapLogic gml;
	
	private boolean stop;
	
	private JMenuBar menuBar;
	
	public GLWindow() {
		super( "Game of life" );
		
		map = new GLMap(350, 200);
		
		gml = new Rule01Logic(5, 10, true);
		
		panel = new GLPanel(map, gml);

		add(panel);
		
		initMenu();

		pack();
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
		 
		initThread();
	}
	
	private void initMenu() {
		//------------------------------------------------
		//action
		JMenuItem play = new JMenuItem("Play");
		JMenuItem stop = new JMenuItem("Stop");
		
		play.addActionListener(new PlayListener());
		stop.addActionListener(new StopListener());
		
		JMenu action = new JMenu("Action");
		action.add(play);
		action.add(stop);
		
		//------------------------------------------------
		//rules
		JMenuItem rule01 = new JMenuItem("Rule 01");
		rule01.addActionListener(new Rule01Listener(this));
		JMenuItem rule02 = new JMenuItem("Rule 02");
		rule02.addActionListener(new Rule02Listener(this));
		JMenuItem rule03 = new JMenuItem("Rule 03");
		rule03.addActionListener(new Rule03Listener(this));
		
		JMenu rules = new JMenu("Rules");
		rules.add(rule01);
		rules.add(rule02);
		rules.add(rule03);
		//------------------------------------------------
		//main menu
		menuBar = new JMenuBar();
		menuBar.add(action);
		menuBar.add(rules);
		setJMenuBar(menuBar);
	}
	
	public void initThread() {	
		new Thread(this).start();
		stop = true;
	}
	
	@Override
	public void run() {
		while(true) {
			if(!stop) {
				panel.update();
				repaint();
			}
			try {
				Thread.sleep(80);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public boolean isStop() {
		return stop;
	}

	public void setStop(boolean stop) {
		this.stop = stop;
	}

	public GLPanel getPanel() {
		return panel;
	}

	public GLMap getMap() {
		return map;
	}

	public GLMapLogic getGml() {
		return gml;
	}	
	
	public void setGml(GLMapLogic gml) {
		this.gml = gml;
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		switch(e.getID()) {
		case GLActions.NEW_RULE:
			initNewRule();
			break;
		}
	}
	
	private void initNewRule() {
		panel = new GLPanel(map, gml);
		gml.generateRandomSet(map);
		stop = true;
		panel.revalidate();
		panel.repaint();
	}
	//=================================================================================
	//LISTENERS
	//=================================================================================

	private class PlayListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent arg0) {
			stop = false;
		}
	}
	
	private class StopListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent arg0) {
			stop = true;
		}
	}
	
	private class RulesListener implements ActionListener {
		protected GLWindow parent;
		
		public RulesListener(GLWindow parent) {
			if(parent == null)
				throw new RuntimeException("parent cannot be null");
			this.parent = parent;
		}
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			initNewRule();
		}
	}
	
	private class Rule01Listener extends RulesListener {
		public Rule01Listener(GLWindow parent) {
			super(parent);
		}

		@Override
		public void actionPerformed(ActionEvent arg0) {
			new Rule01Window(parent);
		}
	}

	private class Rule02Listener extends RulesListener {
		public Rule02Listener(GLWindow parent) {
			super(parent);
		}

		@Override
		public void actionPerformed(ActionEvent arg0) {
			new Rule02Window(parent);
		}
	}
	
	private class Rule03Listener extends RulesListener {
		public Rule03Listener(GLWindow parent) {
			super(parent);
		}

		@Override
		public void actionPerformed(ActionEvent arg0) {
			new Rule03Window(parent);
		}
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		new GLWindow();
	}
}
